package damas.modelo;

import utils.Pair;
import damas.gui.DamasGui;

/**
 * Clase que representa el modelo del juego, contiene todo lo referente a
 * estado, varios m�todos de esta clase llaman o utilizan m�todos de la clase
 * {@code DamasEstado}.
 * <p>
 * Esta clase se encarga principalmente de mantener el estado del juego en
 * relaci�n a jugadores e informaci�n extra para el juego (Como ser el fondo del
 * tablero), todos lo que sea estrictamente estado del problema es
 * responsabilidad de {@code DamasEstado}
 * 
 * @see DamasModelo#mover(utils.Pair, utils.Pair)
 * @see DamasModelo#vacio(utils.Pair)
 * @see DamasModelo#fichaEn(utils.Pair)
 * @see DamasModelo#esDama(utils.Pair)
 * @see DamasModelo#fichasComidas(int)
 * 
 */
public class DamasModelo {
	public static final int NEGRA = 3;
	public static final int ROJA = -3;
	public static final int FONDO_NEGRO = 1;
	public static final int FONDO_BLANCO = 2;
	public static final int DAMA = 5;

	private DamasGui gui;
	private DamasEstado estado;
	private String[] nombresJugadores;
	private int[] coloresJugadores;
	private boolean[] cerebrosJugadores;
	private int[][] fondo;

	/**
	 * Constructor de la clase, crea el fondo del tablero y define valores por
	 * defecto para los jugadores
	 * 
	 * @param estado
	 *            : el estado basico del juego : {@code DamasEstado}
	 * @param gui
	 *            : la interfaz gr�fica del juego : {@code DamasGui}
	 */
	public DamasModelo(DamasEstado estado, DamasGui gui) {
		this.estado = estado;
		this.gui = gui;
		fondo = new int[][] {
				{ FONDO_BLANCO, FONDO_NEGRO, FONDO_BLANCO, FONDO_NEGRO,
						FONDO_BLANCO, FONDO_NEGRO, FONDO_BLANCO, FONDO_NEGRO },
				{ FONDO_NEGRO, FONDO_BLANCO, FONDO_NEGRO, FONDO_BLANCO,
						FONDO_NEGRO, FONDO_BLANCO, FONDO_NEGRO, FONDO_BLANCO },
				{ FONDO_BLANCO, FONDO_NEGRO, FONDO_BLANCO, FONDO_NEGRO,
						FONDO_BLANCO, FONDO_NEGRO, FONDO_BLANCO, FONDO_NEGRO },
				{ FONDO_NEGRO, FONDO_BLANCO, FONDO_NEGRO, FONDO_BLANCO,
						FONDO_NEGRO, FONDO_BLANCO, FONDO_NEGRO, FONDO_BLANCO },
				{ FONDO_BLANCO, FONDO_NEGRO, FONDO_BLANCO, FONDO_NEGRO,
						FONDO_BLANCO, FONDO_NEGRO, FONDO_BLANCO, FONDO_NEGRO },
				{ FONDO_NEGRO, FONDO_BLANCO, FONDO_NEGRO, FONDO_BLANCO,
						FONDO_NEGRO, FONDO_BLANCO, FONDO_NEGRO, FONDO_BLANCO },
				{ FONDO_BLANCO, FONDO_NEGRO, FONDO_BLANCO, FONDO_NEGRO,
						FONDO_BLANCO, FONDO_NEGRO, FONDO_BLANCO, FONDO_NEGRO },
				{ FONDO_NEGRO, FONDO_BLANCO, FONDO_NEGRO, FONDO_BLANCO,
						FONDO_NEGRO, FONDO_BLANCO, FONDO_NEGRO, FONDO_BLANCO }, };
		this.nombresJugadores = new String[] { "player1", "player2" };
		this.coloresJugadores = new int[] { ROJA, NEGRA };
		this.cerebrosJugadores = new boolean[] { false, false };
	}

	/**
	 * Mueve una ficha
	 * 
	 * @param inicio
	 *            : la posici�n actual de la ficha a mover :
	 *            {@code Pair<Integer,Integer>}
	 * @param destino
	 *            : la posici�n a la cual se quiere mover la ficha :
	 *            {@code Pair<Integer,Integer>}
	 * @return true si la movida es parte de una cadena de capturas, si sigue
	 *         jugando el mismo jugador : {@code boolean}
	 * 
	 *         (fila,columna) = (y,x)
	 */
	public boolean mover(Pair<Integer, Integer> inicio,
			Pair<Integer, Integer> destino) {
		// movemos la ficha
		// true ssi comio
		if (estado.mover(inicio, destino)) {
			// ver si puede seguir comiendo
			return (estado.tieneComidaAlcanzable(destino));
		} else {
			return false;
		}
	}

	/**
	 * @param pos
	 *            : una posici�n del tablero : {@code Pair<Integer,Integer>}
	 * @return si el tablero est� libre en {@code pos} : {@code boolean}
	 */
	public boolean vacio(Pair<Integer, Integer> pos) {
		return !estado.hayFichaEnLaCasilla(pos);
	}

	/**
	 * @param pos
	 *            : una posici�n del tablero : {@code Pair<Integer,Integer>}
	 * @return que ficha hay en {@code pos} : {@code int}
	 *         <hr>
	 *         <b>Las respuestas posibles son:
	 *         <li>ficha negra : NEGRA</li>
	 *         <li>ficha roja : ROJA</li>
	 *         <li>dama negra : NEGRA*DAMA</li>
	 *         <li>dama roja : ROJA*DAMA</li>
	 *         <li>ninguna ficha : 0</li></b>
	 */
	public int fichaEn(Pair<Integer, Integer> pos) {
		return estado.getTablero()[pos.getFirstElem()][pos.getSecondElem()];
	}

	/**
	 * @param pos
	 *            : una posici�n del tablero : {@code Pair<Integer,Integer>}
	 * @return true si tablero en {@code pos} es una dama : {@code boolean}
	 */
	public boolean esDama(Pair<Integer, Integer> pos) {
		return !vacio(pos)
				&& ((fichaEn(pos) == ROJA * DAMA) || (fichaEn(pos) == NEGRA
						* DAMA));
	}

	/**
	 * Retorna las fichas comidas por un jugador (segun su color)
	 * 
	 * @param color
	 *            : el jugador del que se intenta averiguar las fichas comidas :
	 *            {@code int}
	 * @return fichas comidas por el jugador
	 *         <hr>
	 *         Este m�todo se llamar�a con
	 *         <li>
	 * 
	 *         <pre>
	 * fichasComidas(DamasModelo.ROJA)
	 * </pre>
	 * 
	 *         </li>
	 *         <li>
	 * 
	 *         <pre>
	 * fichasComidas(DamasModelo.NEGRA)
	 * </pre>
	 * 
	 *         </li>
	 */
	public int fichasComidas(int color) {
		return (color == ROJA ? 12 - this.estado.getContadorNegra()
				: 12 - this.estado.getContadorRoja());
	}

	public DamasEstado obtenerEstado() {
		return this.estado;
	}

	public void definirEstado(DamasEstado estado) {
		this.estado = estado;
	}

	public boolean esMax() {
		return this.estado.isMax();
	}

	public boolean esMin() {
		return this.estado.isMin();
	}

	public boolean ganoMax() {
		return this.estado.maxWins();
	}

	public boolean ganoMin() {
		return this.estado.minWins();
	}

	public boolean juegoTermino() {
		return this.estado.isFinal();

	}

	public int fondoEn(Pair<Integer, Integer> pos) {
		return fondo[pos.getFirstElem()][pos.getSecondElem()];
	}

	public boolean esHumano(int color) {
		int jugador = (coloresJugadores[0] == color ? 0 : 1);
		return !cerebrosJugadores[jugador];
	}

	public String nombreJugador(int color) {
		int jugador = (coloresJugadores[0] == color ? 0 : 1);
		return nombresJugadores[jugador];
	}

	public int colorJugador(int turno) {
		return coloresJugadores[turno];
	}

	public void definirNombre(int jugador, String nombre) {
		this.nombresJugadores[jugador] = nombre;
	}

	public void definirColor(int jugador, int color) {
		this.coloresJugadores[jugador] = color;
	}

	public void definirCerebro(int jugador, boolean cerebro) {
		this.cerebrosJugadores[jugador] = cerebro;
	}

	public void startGUI() {
		this.gui.habilitarTablero();
		this.gui.getJugador1Label().setText(
				nombresJugadores[0]
						+ (cerebrosJugadores[0] ? "(AI)" : "(Human)"));
		this.gui.getJugador2Label().setText(
				nombresJugadores[1]
						+ (cerebrosJugadores[1] ? "(AI)" : "(Human)"));
		this.gui.getColor1Label().setText(
				coloresJugadores[0] == DamasModelo.ROJA ? "ROJAS" : "NEGRAS");
		this.gui.getColor2Label().setText(
				coloresJugadores[1] == DamasModelo.ROJA ? "ROJAS" : "NEGRAS");

		// setea quien es min y max en el estado
		// siempre max son las rojas min las negras

		// el primer jugador no es maquina
		if (!cerebrosJugadores[0] && cerebrosJugadores[1]) {
			if (this.coloresJugadores[0] == DamasModelo.ROJA) {
				this.estado.setMin();
			} else {
				this.estado.setMax();
			}
		} else {
			if (cerebrosJugadores[0] && !cerebrosJugadores[1]) {
				if (this.coloresJugadores[0] == DamasModelo.ROJA) {
					this.estado.setMax();
				} else {
						this.estado.setMin();
					}
			} else{
				if (cerebrosJugadores[0] && cerebrosJugadores[1]) {
					if (this.coloresJugadores[0] == DamasModelo.ROJA) {
						this.estado.setMax();
					} else {
						
							this.estado.setMax();}
						
					
				}
			}
		}
		update();
	}

	public void update() {
		this.gui.update(this);
	}

	public void interaccionTablero(boolean habilitar) {
		this.gui.habilitarInteraccionTablero(habilitar);
	}

	public void habilitarPreferencias() {
		this.gui.habilitarPreferencias(true);
	}

	public void deshabilitarPreferencias() {
		this.gui.habilitarPreferencias(false);
	}

	public void mostrarGUI() {
		this.gui.setEnabled(true);
		this.gui.setVisible(true);
	}

	public void deshabilitarTablero() {
		this.gui.deshabilitarTablero();
	}

	public boolean genereComidaObligatoria() {
		return this.estado.genereMovidaObligatoria;
	}

}
